use crate::adapter::ATAdapter;
use crate::adapter::ATAdapterRecvError;
use crate::adapter::ATAdapterSendError;
use std::thread;
use std::time::Duration;

#[derive(Debug)]
pub struct Usart {
    pub port: Box<dyn serialport::SerialPort>,
    rx_sender: crossbeam_channel::Sender<String>,
    rx_receiver: crossbeam_channel::Receiver<String>,
}

impl Usart {
    pub fn new(port: Box<dyn serialport::SerialPort>) -> Self {
        let (rx_sender, rx_receiver) = crossbeam_channel::bounded(128);
        Usart {
            port,
            rx_sender,
            rx_receiver,
        }
    }

    pub fn start_recv(self) -> Self {
        let _ = self.port.clear(serialport::ClearBuffer::Input);
        let _ = self.port.clear(serialport::ClearBuffer::Output);

        let mut port_cloned = self.port.try_clone().unwrap();
        let rx_sender = self.rx_sender.clone();
        thread::spawn(move || {
            let mut step: u8 = 0;

            let mut recv_buffer: [u8; 1024] = [0; 1024];
            let mut recv_len = 0;

            loop {
                if let Ok(_n) = port_cloned.read(&mut recv_buffer[recv_len..(recv_len + 1)]) {
                    if step == 0 {
                        if recv_buffer[recv_len] == b'\r' {
                            step = 1;
                            continue;
                        }
                    } else {
                        if recv_buffer[recv_len] == b'\n' {
                            if let Ok(s) = String::from_utf8(recv_buffer[..recv_len].to_vec()) {
                                debug!("RX: {:?}", s);
                                let _ = rx_sender.send(s);
                            }
                        } else {
                            error!(
                                "LFCR error: {:?}",
                                String::from_utf8(recv_buffer[..recv_len].to_vec())
                            );
                        }
                        step = 0;
                        recv_len = 0;
                        continue;
                    }
                    if recv_buffer[recv_len].is_ascii() {
                        recv_len += 1;
                    } else {
                        error!("NOT ASCII: {:02X?}", &recv_buffer[..(recv_len + 1)]);
                    }
                    if recv_len == 1024 {
                        recv_len = 0;
                    }
                    continue;
                }
                thread::sleep(Duration::from_millis(1));
            }
        });
        self
    }
}

impl ATAdapter for Usart {
    fn send(&mut self, m: &str) -> Result<usize, ATAdapterSendError> {
        debug!("TX: {:?}", m);
        let mut nbytes = 0;
        if let Ok(n) = self.port.write(m.as_bytes()) {
            nbytes += n;
        } else {
            return Err(ATAdapterSendError::SendError);
        }
        if let Ok(n) = self.port.write(b"\r\n") {
            nbytes += n;
        } else {
            return Err(ATAdapterSendError::SendError);
        }
        Ok(nbytes)
    }

    // fn recv(&mut self) -> Result<String, ATAdapterRecvError> {
    //     match self.rx.recv() {
    //         Ok(s) => return Ok(s),
    //         Err(crossbeam_channel::RecvError) => return Err(ATAdapterRecvError::RecvError),
    //     }
    // }

    fn recv_timeout(&mut self, timeout: Duration) -> Result<String, ATAdapterRecvError> {
        match self.rx_receiver.recv_timeout(timeout) {
            Ok(s) => Ok(s),
            Err(crossbeam_channel::RecvTimeoutError::Timeout) => {
                Err(ATAdapterRecvError::RecvTimeoutError)
            }
            Err(crossbeam_channel::RecvTimeoutError::Disconnected) => {
                Err(ATAdapterRecvError::RecvDisconnected)
            }
        }
    }

    fn try_recv(&mut self) -> Result<String, ATAdapterRecvError> {
        match self.rx_receiver.try_recv() {
            Ok(s) => Ok(s),
            Err(crossbeam_channel::TryRecvError::Empty) => Err(ATAdapterRecvError::RecvEmpty),
            Err(crossbeam_channel::TryRecvError::Disconnected) => {
                Err(ATAdapterRecvError::RecvDisconnected)
            }
        }
    }
}
